﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Web;
using System.Web.Configuration;

using MVCThemes;
using MVCThemes.Interfaces;

using mvcForum.Core.Abstractions.Interfaces;
using mvcForum.Core.Abstractions.Interfaces.DependencyManagement;
using mvcForum.Core.Interfaces.Services;

using mvcForum.Web.Cache;
using mvcForum.Web.Events;
using mvcForum.Web.Interfaces;
using mvcForum.Web.Providers;
using mvcForum.Web.Services;
using mvcForum.Web.Areas.Forum.Controllers;

using SimpleAuthentication.Mvc;

using SimpleLocalisation;
using SimpleLocalisation.Web;
using mvcForum.Core.Interfaces.DependencyManagement;

namespace mvcForum.Web.DependencyBuilders {

	/// <summary>
	/// Dependency builder for MVC Forum's web related dependencies.
	/// </summary>
	public class WebCommonBuilder : mvcForum.Core.Interfaces.DependencyManagement.IDependencyBuilder {

		/// <summary>
		/// Configure method of the WebCommonBuilder class.
		/// Here we wire up everything needed for MVC Forum's website.
		/// </summary>
		/// <param name="container">The dependency container.</param>
		public void Configure(mvcForum.Core.Interfaces.DependencyManagement.IDependencyContainer container) {
			try {
				// Let's get the localisation engine up and running.
				TextManager manager = new TextManager(
					new WebCultureContext(),
					new XmlFileTextSource(() => HttpContext.Current.Server.MapPath("~/app_data/texts")),
					new Language[] { new Language("en-GB") });
				// Let's make it fall back to english if everything else fails!
				//manager.FallbackLanguages = new List<LanguageInfo> { new LanguageInfo { Key = "en-GB" } };

				// The text/localisation manager runs in singleton mode.
				container.RegisterSingleton<TextManager>(manager);
			}
			catch { }

			// Let's put this in request scope, that way we have cached elements per request.
			container.RegisterPerRequest<IPerRequestCache, PerRequestCache>();
			container.RegisterSingleton<IKnownTypeHolder, KnownTypeHolder>();

			container.Register<ITopicService, TopicService>();
			container.Register<IGroupService, GroupService>();
			container.Register<IForumAccessService, ForumAccessService>();
			container.Register<IAttachmentService, AttachmentService>();
			container.Register<IPostService, PostService>();
			container.Register<IUserService, UserService>();

			container.Register<IAuthenticationCallbackProvider, AuthController>();
		}

		public void ValidateRequirements(IList<mvcForum.Core.Interfaces.DependencyManagement.ApplicationRequirement> feedback) {
			// Let's see if we can find a SMTP configuration, we need that to be able to send e-mails.
			Object smtp = ConfigurationManager.GetSection("system.net/mailSettings/smtp");
			if (smtp == null) {
				feedback.Add(new mvcForum.Core.Interfaces.DependencyManagement.ApplicationRequirement { Feedback = "Unable to find a SMTP configuration in the web.config file. MVC Forum will not be able to send e-mails.", Level = RequirementLevel.Warning });
			}
			else {
				feedback.Add(new mvcForum.Core.Interfaces.DependencyManagement.ApplicationRequirement { Feedback = "SMTP configuration located.", Level = RequirementLevel.Info });
			}

			// Can we locate the membership provider configuration?
			Object membership = ConfigurationManager.GetSection("system.web/membership");
			// No membership provider, MVC Forum needs one for working properly.
			if (membership == null) {
				// Let's return a warning!
				feedback.Add(new mvcForum.Core.Interfaces.DependencyManagement.ApplicationRequirement { Feedback = "No membership provider found, MVC Forum can not run without a membership provider configuration.", Level = RequirementLevel.Warning });
			}
			else {
				// Membership provider found, let's get the list of providers.
				MembershipSection memberSection = (MembershipSection)membership;
				// Do we have a default provider configured?
				if (memberSection.Providers[memberSection.DefaultProvider] != null) {
					// Is the default provider the MVC Forum membership provider wrapper?
					if (memberSection.Providers[memberSection.DefaultProvider].Type == String.Format("{0}.{1}", typeof(MembershipProviderWrapper).Namespace, typeof(MembershipProviderWrapper).Name)) {
						// Yes, good! Info for feedback!
						feedback.Add(new mvcForum.Core.Interfaces.DependencyManagement.ApplicationRequirement { Feedback = "Membership provider configuration located.", Level = RequirementLevel.Info });
						// What provider are we wrapping?
						String wrapped = memberSection.Providers[memberSection.DefaultProvider].Parameters.Get("WrappedProvider");
						// Anything?
						if (!String.IsNullOrWhiteSpace(wrapped)) {
							// Do the wrapped provider exist in the list of providers?
							if (memberSection.Providers[wrapped] != null) {
								// Cool, membership provider configuration seems okay!
								feedback.Add(new ApplicationRequirement { Feedback = "The wrapped membership provider was located.", Level = RequirementLevel.Info });
							}
							else {
								// Nope, bad! Warning returned, can't locate the wrapped provider!
								feedback.Add(new ApplicationRequirement { Feedback = String.Format("The wrapper membership provider '{0}' was not found.", wrapped), Level = RequirementLevel.Warning });
							}
						}
						else {
							// No WrappedProvider attribute? Warning!
							feedback.Add(new ApplicationRequirement { Feedback = "The membership provider wrapper requires 'WrappedProvider' attribute.", Level = RequirementLevel.Warning });
						}
					}
					else {
						// Wrong provider! Warning!
						feedback.Add(new ApplicationRequirement { Feedback = String.Format("The default membership provider should be {0}, that is the only way MVC Forum will work.", typeof(MembershipProviderWrapper).Name), Level = RequirementLevel.Warning });
					}
				}
				else {
					// No default provider, let's return a warning!
					feedback.Add(new ApplicationRequirement { Feedback = "No default membership provider found, MVC Forum can not run without a membership provider configuration.", Level = RequirementLevel.Warning });
				}
			}

			// Can we locate the role manager provider configuration?
			Object roles = ConfigurationManager.GetSection("system.web/roleManager");
			// Did we get it?
			if (roles == null) {
				// Nope, role provider missing, warning!
				feedback.Add(new mvcForum.Core.Interfaces.DependencyManagement.ApplicationRequirement { Feedback = "No role manager provider found, MVC Forum can not run without a role manager provider configuration.", Level = RequirementLevel.Warning });
			}
			else {
				// Role section found!
				RoleManagerSection roleSection = (RoleManagerSection)roles;
				// Do we have a default role provider configured?
				if (roleSection.Providers[roleSection.DefaultProvider] != null) {
					// TODO:
					//if (roleSection.Providers[roleSection.DefaultProvider].Type == String.Format("{0}.{1}", typeof(MVCForumRoleProvider).Namespace, typeof(MVCForumRoleProvider).Name)) {
					//    feedback.Add(new ApplicationRequirement { Feedback = "Role manager provider configuration located.", Level = RequirementLevel.Info });
					//}
					//else {
					//    feedback.Add(new ApplicationRequirement { Feedback = String.Format("The default role manager provider should be {0}, that is the only way MVC Forum will work (for now).", typeof(MVCForumRoleProvider).Name), Level = RequirementLevel.Warning });
					//}
				}
				else {
					// No default role provider, warning!
					feedback.Add(new mvcForum.Core.Interfaces.DependencyManagement.ApplicationRequirement { Feedback = "No default role manager provider found, MVC Forum can not run without a role manager provider configuration.", Level = RequirementLevel.Warning });
				}
			}
		}
	}
}